In [173]:
__author__ = 'Stephanie Juneau, NOAO Data Lab Team'
__version__ = '20171101' # yyyymmdd
__datasets__ = ['des_dr1']  # enter used datasets by hand;
                           # for a list of available datasets, see cell "Available datasets in Data Lab" further below

Star/Galaxy/QSO Classification in the Dark Energy Survey (DES)ΒΆ

by StΓ©phanie Juneau, Knut Olsen, Robert Nikutta and the NOAO Data Lab Team

In this notebook, we investigate the optical colors of astronomical sources detected in the Dark Energy Survey (DES), an imaging survey conducted with the Dark Energy Camera (DECam) on the 4-meter Blanco telescope. The first data release, DR1, comprises ~400 millions stars, galaxies and quasars (or QSOs: Quasi-Stellar Objects).

NOAO Data Lab products and services used here:

  • the DES DR1 database
  • Jupyter Notebook Server
  • Query Manager

Below, we query the database, compute colors, plot a few color combinations, and take into account the source shapes as defined from the spread of the light profiles and a pre-computed star-galaxy classifier, in order to differentiate between object classes.

0. Disclaimer & attributionΒΆ

If you use this notebook for your published science, please acknowledge the following:

1. IntroductionΒΆ

An imaging survey includes a zoo of different astronomical objects. There are foreground stars from our own Milky Way galaxies, and background galaxies at various distances, including QSOs (quasi-stellar objects) with actively accreting supermassive black holes. In this Notebook, we aim to distinguish between object classes using combinations of colors and shape parameters.

1.1 Magnitudes and ColorsΒΆ

Magnitudes are obtained through a set of filters similar to the u,g,r,i,z set used for SDSS. In this work, we use g,r,z from the Dark Energy Camera (DECam)

Colors are defined as a difference between magnitudes in two bands. A "redder" color means that the object is comparatively brighter in the redder (i.e., longer wavelength) band. Conversely, a "bluer" color means that the object is comparatively brighther in the bluer (i.e., shorter wavelenght) band.

We will use the following colors:

  • *g-r*
  • *r-z*

1.2 Object Shapes/TypesΒΆ

The object shape (2D light profile) can be defined with a size and ellipticity. In this Notebook, we are interested in distinguishing between stars as point sources, and galaxies as extended sources.

  • *kron_radius*: Kron radius in pixels
  • *spread_model_X*: star-galaxy classifier comparing extended model to PSF model. Value is given for each band X = g, r, i, z, y
  • *class_star_X*: value ranging from 0.0 (not a star) to 1.0 (star), for each band X = g, r, i, z, y

The value of spread_model is near zero for a point source (star or QSO), positive for an extended source (galaxy), negative for an artefact smaller than the PSF (e.g., bad pixel or cosmic ray). More information about the spread_model can be found in Desai et al (2012), and Soumagnac et al (2015).

2. Imports and setupΒΆ

In [1]:
# Python 2/3 compatibility
from __future__ import print_function # to use print() as a function in Python 2
#from __future__ import division  # if you need Python 3 division behavior in Python 2

try:
    input = raw_input # use 'input' function in both Python 2 and 3
except NameError:
    pass

# std lib
from getpass import getpass
from cStringIO import StringIO  #C script to handle string format

# 3rd party
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.ticker import NullFormatter
from astropy.utils.data import download_file  #import file from URL
from scipy.stats import binned_statistic_2d
%matplotlib inline
from astropy.table import Table

# Data Lab
from dl import authClient as ac, queryClient as qc, storeClient as sc, helpers

print('Done importing')
Done importing

3. AuthenticationΒΆ

In [2]:
# Python 2/3 compatibility
try:
    input = raw_input
except NameError:
    pass

# Either get token for anonymous user
token = ac.login('anonymous')

# ... or for authenticated user
#token = ac.login(input("Enter user name: "),getpass("Enter password: "))

4. Available datasets in Data LabΒΆ

In [3]:
# these schemas are not astronomical datasets
_remove = set(['ivao','ivao_smash','tap_schema','schema'])

# get all schemas from DB
_schemas = set(qc.query(token,sql='SELECT schema FROM tbl_stat').split())

# remove non-astro schemas
_alldatasets = sorted(list(_schemas - _remove))
print("Datasets available in Data Lab (with current profile):\n", _alldatasets)

# TODO: Enter used datasets by hand in the list __datasets__ in the very first cell above
Datasets available in Data Lab (with current profile):
 [u'allwise', u'des_sva1', u'gaia_dr1', u'ivoa', u'ivoa_smash', u'ls_dr3', u'ls_dr4', u'ls_dr5', u'neo_dr1', u'phat_v2', u'sdss_dr13', u'smash_dr1', u'twomass', u'usno']

5. Query DES Photometry CatalogΒΆ

The photometry is derived from Tractor modeling of sources, and the database includes model photometry, type (shape), as well as aperture photometry in various aperture sizes. In this work, we will use Tractor model magnitudes.

The database is called des_dr1 and includes several tables. We will use the main table. The column names and descriptions can be found from the Data Lab Query Interface or using the Table Access Protocol (TAP) service with, e.g., TOPCAT. In both cases, we are interested in des_dr1.main.

In [9]:
# Write query statement (sql) as a string
# NOTE: triple quotes allow us to break the string on multiple lines
query = """
        SELECT mag_auto_g as gmag, mag_auto_r as rmag, mag_auto_z as zmag, 
               mag_auto_i as imag, mag_auto_y as ymag, 
               kron_radius, spread_model_g, class_star_g, spread_model_r, class_star_r, 
               spread_model_z, class_star_z, 
               flux_auto_g/fluxerr_auto_g as snr_g2, snr_g, snr_r, snr_z, ra, dec
        FROM des_dr1.main 
        WHERE (fluxerr_auto_g>0 and fluxerr_auto_r>0 and fluxerr_auto_z>0)
        LIMIT 800000"""

# mag_auto_g,r,i,z,y = AB magnitudes in DECam g,r,i,z,y bands
# kron_radius        = Kron radius from SExtractor (pixels)
# spread_model_g,r,z = star/galaxy classifier quantifying light profile relative to PSF
# class_star_g,r,z   = star/extended source classifier (from 0 to 1)
# snr_g,r,z          = computed signal-to-noise ratios (S/N) in g,r,z bands
# ra,dec             = celestial coordinates
#
# WHERE: requirement that error>0 (to avoid dividing by zero) in g,r,z bands
# LIMIT: returns 200,000 rows that satisfy the query

print(query)
        SELECT mag_auto_g as gmag, mag_auto_r as rmag, mag_auto_z as zmag, 
               mag_auto_i as imag, mag_auto_y as ymag, 
               kron_radius, spread_model_g, class_star_g, spread_model_r, class_star_r, 
               spread_model_z, class_star_z, 
               flux_auto_g/fluxerr_auto_g as snr_g2, snr_g, snr_r, snr_z, ra, dec
        FROM des_dr1.main 
        WHERE (fluxerr_auto_g>0 and fluxerr_auto_r>0 and fluxerr_auto_z>0)
        LIMIT 1000
In [10]:
%%time
# Execute the Query synchronously if short (e.g., LIMIT<=100,000)
response = qc.query(token, sql=query, fmt='csv')

print('Time')
Time
CPU times: user 22 ms, sys: 3 ms, total: 25 ms
Wall time: 122 ms
In [11]:
# Reformat output into a Pandas Data Frame
df = helpers.convert(response,'pandas')
df_all = df

# Print a few rows from the result data frame
print(df[:5])
len(df)
Returning Pandas dataframe
      gmag     rmag     zmag     imag     ymag  kron_radius  spread_model_g  \
0  24.4437  23.9468  23.2600  23.6643  25.8593      6.42620        0.013518   
1  23.3737  22.9202  21.8039  22.6759  21.7348      4.85636        0.019678   
2  20.7794  20.2667  20.0218  20.0769  20.0116      3.50000        0.026783   
3  25.0834  24.7643  23.9921  24.2425  23.0809      8.69944       -0.005559   
4  23.8613  23.3936  23.9431  23.3380  23.5155      4.83126        0.024890   

   class_star_g  spread_model_r  class_star_r  spread_model_z  class_star_z  \
0      0.499239       -0.065032      0.592062       -0.012731      0.521042   
1      0.000230        0.012336      0.021711        0.018432      0.000216   
2      0.027387        0.024986      0.028260        0.029047      0.002056   
3      0.365523        0.010782      0.459898        0.002191      0.476096   
4      0.003332        0.007202      0.109914        0.002163      0.004362   

     snr_g2  snr_g  snr_r  snr_z         ra        dec  
0   5.45102    NaN    NaN    NaN  73.283623 -32.340628  
1   9.63319    NaN    NaN    NaN  73.282368 -32.339879  
2  79.31590    NaN    NaN    NaN  73.283778 -32.339194  
3   4.46721    NaN    NaN    NaN  73.273671 -32.334241  
4   7.48959    NaN    NaN    NaN  73.280253 -32.333032  
Out[11]:
1000

6. Plot ResultsΒΆ

6.1 Optical Color-Color DiagramΒΆ

In [83]:
# Select range of interest
thres = 5.   #threshold value for S/N (here, making it more stringent than query)
keep = (df['snr_g']>thres)&(df['snr_r']>thres)&(df['snr_z']>thres)

# Colors
g_r   = df['gmag'][keep] - df['rmag'][keep]
r_z   = df['rmag'][keep] - df['zmag'][keep]

r_i   = df['rmag'][keep] - df['imag'][keep]
i_z   = df['imag'][keep] - df['zmag'][keep]
z_y   = df['zmag'][keep] - df['ymag'][keep]

len(g_r)

# Classification per object type
#objtype = result['type'][keep]
Out[83]:
243892
In [80]:
col0 = r_z   #r-z color
col1 = g_r   #g-r color

# 2D-histogram of objects
fig, ax1 = plt.subplots(1, 1, figsize=(9, 8))
im1 = ax1.hexbin(col0, col1, bins='log', cmap=plt.cm.viridis,
               mincnt=1, extent=(-1., 3, -1., 3))
ax1.set_xlabel('r-z',fontsize=20)
ax1.set_ylabel('g-r',fontsize=20)

#color bar
cb = plt.colorbar(im1,label='log(N)')

6.2 Morphological ParametersΒΆ

g bandΒΆ

In [85]:
# invalid mags are set to 99 -> mag_auto_X < 90
# spread_model_X is valid at abs(spread_model)<1
# require S/N>5 in the g band
df=df[(df['gmag']<90) & (df['imag']<90) & (df['spread_model_g']>(-1)) & \
      (df['rmag']<90) & (df['zmag']<90) & (df['spread_model_g']<1) & \
      ((df['snr_g'])>5)]

fig = plt.figure(figsize=(8*2,8*3))
ax = fig.add_subplot(3,2,1)
ax.hexbin(df['gmag'],df['spread_model_g'],gridsize=200,bins='log',mincnt=1,extent=(12,26,-0.05,0.05))
ax.set_xlabel('g',fontsize=20)
ax.set_ylabel('spread_model_g',fontsize=20)
ax.tick_params(labelsize=10)

ax2 = fig.add_subplot(3,2,2)
ax2.hexbin(df['kron_radius'],df['spread_model_g'],gridsize=200,bins='log',mincnt=1,extent=(0,10,-0.1,0.1))
ax2.set_xlabel('Kron radius',fontsize=20)
ax2.set_ylabel('spread_model_g',fontsize=20)
ax2.tick_params(labelsize=10)

ax3 = fig.add_subplot(3,2,3)
ax3.hexbin(df['gmag'],df['kron_radius'],gridsize=200,bins='log',mincnt=1,extent=(12,26,0,10))
ax3.set_xlabel('g',fontsize=20)
ax3.set_ylabel('Kron radius',fontsize=20)
ax3.tick_params(labelsize=10)

ax4 = fig.add_subplot(3,2,4)
ax4.hexbin(df['kron_radius'],df['class_star_g'],gridsize=200,bins='log',mincnt=1,extent=(0,10,0,1))
ax4.set_xlabel('Kron radius',fontsize=20)
ax4.set_ylabel('Class_star_g',fontsize=20)
ax4.tick_params(labelsize=10)


ax5 = fig.add_subplot(3,2,5)
ax5.hexbin(df['gmag'],df['class_star_g'],gridsize=200,bins='log',mincnt=1,extent=(12,26,0,1))
ax5.set_xlabel('g',fontsize=20)
ax5.set_ylabel('Class_star_g',fontsize=20)
ax5.tick_params(labelsize=10)

ax6 = fig.add_subplot(3,2,6)
ax6.hexbin(df['spread_model_g'],df['class_star_g'],gridsize=200,bins='log',mincnt=1,extent=(-0.025,0.025,0,1))
ax6.set_xlabel('spread_model_g',fontsize=20)
ax6.set_ylabel('Class_star_g',fontsize=20)
ax6.tick_params(labelsize=10)
In [7]:
#Star-Galaxy Separation (QSOs mixed in)
star = (np.abs(df['spread_model_g'])<0.01) & (df['class_star_g']>0.1) & (df['kron_radius']<4)
dfstar = df[star]
dfgal  = df[~star]
NameErrorTraceback (most recent call last)
<ipython-input-7-3b2e5e376926> in <module>()
      1 #Star-Galaxy Separation (QSOs mixed in)
----> 2 star = (np.abs(df['spread_model_g'])<0.01) & (df['class_star_g']>0.1) & (df['kron_radius']<4)
      3 dfstar = df[star]
      4 dfgal  = df[~star]

NameError: name 'df' is not defined

r bandΒΆ

In [104]:
# reset df
df = df_all

# invalid mags are set to 99 -> mag_auto_X < 90
# spread_model_X is valid at abs(spread_model)<1
# require S/N>5 in the r band
df=df[(df['gmag']<90) & (df['imag']<90) & (df['spread_model_r']>(-1)) & \
      (df['rmag']<90) & (df['zmag']<90) & (df['spread_model_r']<1) & \
      ((df['snr_r'])>5)]

fig = plt.figure(figsize=(8*2,8*3))
ax = fig.add_subplot(3,2,1)
ax.hexbin(df['rmag'],df['spread_model_r'],gridsize=200,bins='log',mincnt=1,extent=(12,26,-0.05,0.05))
ax.set_xlabel('r',fontsize=20)
ax.set_ylabel('spread_model_r',fontsize=20)
ax.tick_params(labelsize=10)

ax2 = fig.add_subplot(3,2,2)
ax2.hexbin(df['kron_radius'],df['spread_model_r'],gridsize=200,bins='log',mincnt=1,extent=(0,10,-0.1,0.1))
ax2.set_xlabel('Kron radius',fontsize=20)
ax2.set_ylabel('spread_model_r',fontsize=20)
ax2.tick_params(labelsize=10)

ax3 = fig.add_subplot(3,2,3)
ax3.hexbin(df['rmag'],df['kron_radius'],gridsize=200,bins='log',mincnt=1,extent=(12,26,0,10))
ax3.set_xlabel('r',fontsize=20)
ax3.set_ylabel('Kron radius',fontsize=20)
ax3.tick_params(labelsize=10)

ax4 = fig.add_subplot(3,2,4)
ax4.hexbin(df['kron_radius'],df['class_star_r'],gridsize=200,bins='log',mincnt=1,extent=(0,10,0,1))
ax4.set_xlabel('Kron radius',fontsize=20)
ax4.set_ylabel('Class_star_r',fontsize=20)
ax4.tick_params(labelsize=10)


ax5 = fig.add_subplot(3,2,5)
ax5.hexbin(df['rmag'],df['class_star_r'],gridsize=200,bins='log',mincnt=1,extent=(12,26,0,1))
ax5.set_xlabel('r',fontsize=20)
ax5.set_ylabel('Class_star_r',fontsize=20)
ax5.tick_params(labelsize=10)

ax6 = fig.add_subplot(3,2,6)
ax6.hexbin(df['spread_model_r'],df['class_star_r'],gridsize=200,bins='log',mincnt=1,extent=(-0.025,0.025,0,1))
ax6.set_xlabel('spread_model_r',fontsize=20)
ax6.set_ylabel('Class_star_r',fontsize=20)
ax6.tick_params(labelsize=10)

z bandΒΆ

In [106]:
# reset df
df = df_all

# invalid mags are set to 99 -> mag_auto_X < 90
# spread_model_X is valid at abs(spread_model)<1
# require S/N>5 in the z band
df=df[(df['gmag']<90) & (df['imag']<90) & (df['spread_model_z']>(-1)) & \
      (df['rmag']<90) & (df['zmag']<90) & (df['spread_model_z']<1) & \
      ((df['snr_z'])>5)]

fig = plt.figure(figsize=(8*2,8*3))
ax = fig.add_subplot(3,2,1)
ax.hexbin(df['zmag'],df['spread_model_z'],gridsize=200,bins='log',mincnt=1,extent=(12,26,-0.05,0.05))
ax.set_xlabel('z',fontsize=20)
ax.set_ylabel('spread_model_z',fontsize=20)
ax.tick_params(labelsize=10)

ax2 = fig.add_subplot(3,2,2)
ax2.hexbin(df['kron_radius'],df['spread_model_z'],gridsize=200,bins='log',mincnt=1,extent=(0,10,-0.1,0.1))
ax2.set_xlabel('Kron radius',fontsize=20)
ax2.set_ylabel('spread_model_z',fontsize=20)
ax2.tick_params(labelsize=10)

ax3 = fig.add_subplot(3,2,3)
ax3.hexbin(df['zmag'],df['kron_radius'],gridsize=200,bins='log',mincnt=1,extent=(12,26,0,10))
ax3.set_xlabel('z',fontsize=20)
ax3.set_ylabel('Kron radius',fontsize=20)
ax3.tick_params(labelsize=10)

ax4 = fig.add_subplot(3,2,4)
ax4.hexbin(df['kron_radius'],df['class_star_z'],gridsize=200,bins='log',mincnt=1,extent=(0,10,0,1))
ax4.set_xlabel('Kron radius',fontsize=20)
ax4.set_ylabel('Class_star_z',fontsize=20)
ax4.tick_params(labelsize=10)


ax5 = fig.add_subplot(3,2,5)
ax5.hexbin(df['zmag'],df['class_star_z'],gridsize=200,bins='log',mincnt=1,extent=(12,26,0,1))
ax5.set_xlabel('z',fontsize=20)
ax5.set_ylabel('Class_star_z',fontsize=20)
ax5.tick_params(labelsize=10)

ax6 = fig.add_subplot(3,2,6)
ax6.hexbin(df['spread_model_z'],df['class_star_z'],gridsize=200,bins='log',mincnt=1,extent=(-0.025,0.025,0,1))
ax6.set_xlabel('spread_model_z',fontsize=20)
ax6.set_ylabel('Class_star_z',fontsize=20)
ax6.tick_params(labelsize=10)

Combining bandsΒΆ

Above, the spread_model yields the best separation in the z band, as well as the fewest ridge features in distribution of class_star. On the other hand, the g band shows the most overlap in spread_model values at faint magnitudes, and the most striking ridges in the distribution of class_star. For testing purposes, let's see what happens for cases that have detections in all 3 g,r,z bands, and then when the classification agrees between the bands.

First, we plot again the "worst" case (g band) but requiring objects to have S/N>5 in all of g,r,z bands.

In [111]:
# reset df
df = df_all

# invalid mags are set to 99 but requiring S/N>5 will only keep valid mags
# spread_model_X is valid at abs(spread_model)<1
# require S/N>5 in the g, r, z band
df=df[(df['spread_model_g']>(-1)) & (df['spread_model_g']<1) & \
      (df['snr_g']>5) & (df['snr_r']>5) & (df['snr_z']>5)]

fig = plt.figure(figsize=(8*2,8*3))
ax = fig.add_subplot(3,2,1)
ax.hexbin(df['gmag'],df['spread_model_g'],gridsize=200,bins='log',mincnt=1,extent=(12,26,-0.05,0.05))
ax.set_xlabel('g',fontsize=20)
ax.set_ylabel('spread_model_g',fontsize=20)
ax.tick_params(labelsize=10)

ax2 = fig.add_subplot(3,2,2)
ax2.hexbin(df['kron_radius'],df['spread_model_g'],gridsize=200,bins='log',mincnt=1,extent=(0,10,-0.1,0.1))
ax2.set_xlabel('Kron radius',fontsize=20)
ax2.set_ylabel('spread_model_g',fontsize=20)
ax2.tick_params(labelsize=10)

ax3 = fig.add_subplot(3,2,3)
ax3.hexbin(df['gmag'],df['kron_radius'],gridsize=200,bins='log',mincnt=1,extent=(12,26,0,10))
ax3.set_xlabel('g',fontsize=20)
ax3.set_ylabel('Kron radius',fontsize=20)
ax3.tick_params(labelsize=10)

ax4 = fig.add_subplot(3,2,4)
ax4.hexbin(df['kron_radius'],df['class_star_g'],gridsize=200,bins='log',mincnt=1,extent=(0,10,0,1))
ax4.set_xlabel('Kron radius',fontsize=20)
ax4.set_ylabel('Class_star_g',fontsize=20)
ax4.tick_params(labelsize=10)


ax5 = fig.add_subplot(3,2,5)
ax5.hexbin(df['gmag'],df['class_star_g'],gridsize=200,bins='log',mincnt=1,extent=(12,26,0,1))
ax5.set_xlabel('g',fontsize=20)
ax5.set_ylabel('Class_star_g',fontsize=20)
ax5.tick_params(labelsize=10)

ax6 = fig.add_subplot(3,2,6)
ax6.hexbin(df['spread_model_g'],df['class_star_g'],gridsize=200,bins='log',mincnt=1,extent=(-0.025,0.025,0,1))
ax6.set_xlabel('spread_model_g',fontsize=20)
ax6.set_ylabel('Class_star_g',fontsize=20)
ax6.tick_params(labelsize=10)

The test above resulted in cleaner plots with fewer ridges on the class_star parameter.

Next, let's test what happens in cases with agreement or disagreement of the value of class_star between bands.

In [125]:
def plot_spread_mag(df_input,i,label=None,**kwargs):
    ax = fig.add_subplot(2,2,i+1)
    ax.hexbin(df_input['gmag'],df_input['spread_model_g'],gridsize=200,bins='log',mincnt=1,extent=(12,26,-0.05,0.05))
    ax.set_xlabel('g',fontsize=20)
    ax.set_ylabel('spread_model_g',fontsize=20)
    ax.tick_params(labelsize=10)
    if label is not None:
        ax.text(0.1,0.1,label,transform=ax.transAxes,fontsize=18,color='red',backgroundcolor='white')
In [130]:
# reset df
df = df_all

# invalid mags are set to 99 -> mag_auto_X < 90
# spread_model_X is valid at abs(spread_model)<1
# require S/N>5 in the g, r, z band
df=df[(df['spread_model_g']>(-1)) & (df['spread_model_g']<1) & \
      (df['snr_g']>5) & (df['snr_r']>5) & (df['snr_z']>5)]

df_gal    = df[(df['class_star_g']<0.5) & (df['class_star_r']<0.5) & (df['class_star_z']<0.5)]
df_notok  = df[(df['class_star_g']<0.5) & ((df['class_star_r']>0.5) | (df['class_star_z']>0.5))]
df_star   = df[(df['class_star_g']>0.5) & (df['class_star_r']>0.5) & (df['class_star_z']>0.5)]
df_notok2 = df[(df['class_star_g']>0.5) & ((df['class_star_r']<0.5) | (df['class_star_z']<0.5))]

fig = plt.figure(figsize=(7*2,7*2))

plot_spread_mag(df_gal,0,label='Galaxies (good)')
plot_spread_mag(df_star,1,label='Stars (good)')
plot_spread_mag(df_notok,2,label='Galaxies (bad)')
plot_spread_mag(df_notok2,3,label='Stars (bad)')

outfile = 'class_star_g_TESTS.png'
fig.savefig(outfile, bbox_inches='tight')

6.3 Optical Color-Color Diagram with New Sample DefinitionΒΆ

In [171]:
def plot_grz(df_input,i,label=None,**kwargs):
    col0 = df_input['rmag'] - df_input['zmag']   #r-z color
    col1 = df_input['gmag'] - df_input['rmag']   #g-r color
    
    # 2D-histogram of objects
    ax = fig.add_subplot(2,2,i+1)
    ax.hexbin(col0, col1, bins='log', cmap=plt.cm.viridis, gridsize=140, 
               mincnt=1, extent=(-1., 3, -1., 3))
    ax.set_xlabel('r-z',fontsize=20)
    ax.set_ylabel('g-r',fontsize=20)

    if label is not None:
        ax.text(0.1,0.9,label,transform=ax.transAxes,fontsize=16,color='red',backgroundcolor='white')
        
    #color bar
#    cb = plt.colorbar(im1,label='log(N)')
In [172]:
fig = plt.figure(figsize=(7*2,7*2))

plot_grz(df_gal,0,label='Galaxies (good)')
plot_grz(df_star,1,label='Stars (good)')
plot_grz(df_notok,2,label='Galaxies (bad)')
plot_grz(df_notok2,3,label='Stars (bad)')

outfile = 'grz_DESDR1.png'
fig.savefig(outfile, bbox_inches='tight')

The galaxy branch and the stellar locus on the g-r vs. r-z plane are much cleaner. However, it is not clear what happens to the QSO's. It could be that they are mostly in the "cloud" below the branches and most obvious in the panel labeled "Stars (bad)". This means that they would look like a star in g but not in either r or z. At a fixed r-z, QSOs would be bluer than stars in g-r. One could investigate with spectroscopy or templates to confirm.

6.4 Comparison with LS + SDSSΒΆ

For reference, this is a figure with LS (DECaLS) photometry for SDSS DR12 spectral classification (comparatively bright objects).

**Figure:** Color-color diagrams of DECaLS photometry split by SDSS spectral classes. Slightly modified version of figure by Bela Abolfathi (UC Irvine).

6.5 DES DR1 with g<22ΒΆ

In [179]:
# Repeat above with with gmag < 22 as in SDSS/BOSS DR12Q

g22_gal    = df[(df['class_star_g']<0.5) & (df['class_star_r']<0.5) & (df['class_star_z']<0.5) & (df['gmag']<22.)]
g22_notok  = df[(df['class_star_g']<0.5) & ((df['class_star_r']>0.5) | (df['class_star_z']>0.5)) & (df['gmag']<22.)]
g22_star   = df[(df['class_star_g']>0.5) & (df['class_star_r']>0.5) & (df['class_star_z']>0.5) & (df['gmag']<22.)]
g22_notok2 = df[(df['class_star_g']>0.5) & ((df['class_star_r']<0.5) | (df['class_star_z']<0.5)) & (df['gmag']<22.)]

fig = plt.figure(figsize=(7*2,7*2))

plot_grz(g22_gal,0,label='Galaxies (good)')
plot_grz(g22_star,1,label='Stars (good)')
plot_grz(g22_notok,2,label='Galaxies (bad)')
plot_grz(g22_notok2,3,label='Stars (bad)')

outfile = 'grz_DESDR1_gLT22.png'
fig.savefig(outfile, bbox_inches='tight')

NOTES: In the panel above, the cloud of points near the bottom left tip of the stellar locus may include some quasars.

6.6 DES DR1 with g>23ΒΆ

In [180]:
# Repeat above with with gmag > 22 (fainter than SDSS/BOSS DR12Q)

g23_gal    = df[(df['class_star_g']<0.5) & (df['class_star_r']<0.5) & (df['class_star_z']<0.5) & (df['gmag']>23.)]
g23_notok  = df[(df['class_star_g']<0.5) & ((df['class_star_r']>0.5) | (df['class_star_z']>0.5)) & (df['gmag']>23.)]
g23_star   = df[(df['class_star_g']>0.5) & (df['class_star_r']>0.5) & (df['class_star_z']>0.5) & (df['gmag']>23.)]
g23_notok2 = df[(df['class_star_g']>0.5) & ((df['class_star_r']<0.5) | (df['class_star_z']<0.5)) & (df['gmag']>23.)]

fig = plt.figure(figsize=(7*2,7*2))

plot_grz(g23_gal,0,label='Galaxies (good)')
plot_grz(g23_star,1,label='Stars (good)')
plot_grz(g23_notok,2,label='Galaxies (bad)')
plot_grz(g23_notok2,3,label='Stars (bad)')

outfile = 'grz_DESDR1_gGT23.png'
fig.savefig(outfile, bbox_inches='tight')

6.7 Class_star ComparisonΒΆ

We compare, for the 4 categories defined above, the class_star values between g and r bands, and between g and z bands.

In [155]:
def plot_class_star_gr(df_input,i,label=None,**kwargs):
    ax = fig.add_subplot(2,4,i+1)
    ax.hexbin(df_input['class_star_r'],df_input['class_star_g'],gridsize=200,bins='log',mincnt=1,extent=(0,1,0,1.2))
    ax.set_xlabel('Class_star_r',fontsize=10)
    ax.set_ylabel('Class_star_g',fontsize=10)
    ax.tick_params(labelsize=10)
    if label is not None:
        ax.text(0.1,0.9,label,transform=ax.transAxes,fontsize=16,color='red',backgroundcolor='white')
In [156]:
def plot_class_star_gz(df_input,i,label=None,**kwargs):
    ax = fig.add_subplot(2,4,i+1)
    ax.hexbin(df_input['class_star_z'],df_input['class_star_g'],gridsize=200,bins='log',mincnt=1,extent=(0,1,0,1.2))
    ax.set_xlabel('Class_star_z',fontsize=10)
    ax.set_ylabel('Class_star_g',fontsize=10)
    ax.tick_params(labelsize=10)
    if label is not None:
        ax.text(0.1,0.9,label,transform=ax.transAxes,fontsize=16,color='red',backgroundcolor='white')
In [157]:
fig = plt.figure(figsize=(4*4,4.5*2))

plot_class_star_gr(df_gal,0,label='Galaxies (good)')
plot_class_star_gr(df_star,1,label='Stars (good)')
plot_class_star_gr(df_notok,2,label='Galaxies (bad)')
plot_class_star_gr(df_notok2,3,label='Stars (bad)')

plot_class_star_gz(df_gal,4,label='Galaxies (good)')
plot_class_star_gz(df_star,5,label='Stars (good)')
plot_class_star_gz(df_notok,6,label='Galaxies (bad)')
plot_class_star_gz(df_notok2,7,label='Stars (bad)')

outfile = 'class_star_g_COMPARE.png'
fig.savefig(outfile, bbox_inches='tight')

ReferencesΒΆ

Soumagnac et al (2015)

Desai et al (2012)